package org.NooLab.demotexx;



import processing.core.PApplet;


import org.NooLab.utilities.files.DFutils;
import org.NooLab.utilities.logging.LogControl;



import org.NooLab.texx.app.*;
import org.NooLab.texx.app.up.IniProperties;
import org.NooLab.texx.app.up.TexxStartup;
import org.NooLab.texx.* ;
import org.NooLab.texx.components.*;
import org.NooLab.texx.properties.PersistenceSettings;
import org.NooLab.texx.properties.TexxControlProperties;
import org.NooLab.texx.properties.TexxProperties;

/*
 * see:
           http://code.google.com/p/hypergraphdb/wiki/WordNet
           http://code.google.com/p/disko/wiki/InitialHyperGraphDB

 */

/**
 *   TODO
 *           - a pool of users to avoid collisions of processes; (for docoserv and for texx)
 *             each process can ask for the next free login
 *             (to be provided by database wrapper...)
 *              
 */
public class Texx_Application_Applet extends PApplet{

	private static final long serialVersionUID = -1206243743183135630L;

	TexxInstance texxInstance ;
	String sourceForProperties = "" ;
	PApplet applet;

	
	public void setup(){
		 
		applet = this;
		background( 208,188,188);
		 
		
		try {
			TexxStartup.setApplicationID("txapplet", this.getClass());
		
		} catch (Exception e) {
			System.err.println(e.getMessage());
			return;
		}
		  
		showKeyCommands();
		
		
		draw();
		
		// start this in its own thread...
		
		// use LogControl to control output of log messages
		LogControl.globeScope = 2; // 1=local definitions  default = 2
		LogControl.Level = 2 ;     // the larger the more detailed logging... (could be really verbose!)
  
		// testPowerSet();
		
	}
	
	public void draw(){
		background( 178,228,198);
	}

	private void showKeyCommands(){

		println();
		println("Welcome to Texx Extractor!\n");
		println("the following key commands are available for minimalistic user-based control...");
		println();
		println("   b  ->  start text extraction as a batch process, taking sources from the DocumentObserver \n"+
				"          and running as a service ");
		println("   t  ->  start text extraction, start from scratch by importing the 'text' file ");
		println("   B  ->  start text extraction as a batch process, taking sources from the source directory ");
		println();
		println("   d  ->  open another text source ");
		println("   o  ->  open another project ");
		println("   p  ->  select a different base folder (=project space) for all projects ");
		println("   P^ ->  create a new project in the project space, the data file must exist somewhere to copy from! ");
		println();
		println("   z  ->  interrupt the current process, export current results and write persistent models ");
		println();
		println("   x  ->  exit");
		println();
		println("------------------------------------------------------------------");
		println();

		_showCurrentInputSettings();
	}
	
	private void _showCurrentInputSettings(){
		String qs="";
		if (TexxStartup.isDataSetAvailable()==false){
			qs = "not " ;
		}
		println("current project : "+ TexxStartup.getLastProjectName()+ ",  data are "+qs+"available.");
		if (qs.length()==0){
			println("data source     : "+ TexxStartup.getLastDataSet() ) ;
			String dir = DFutils.createPath( IniProperties.fluidSomProjectBasePath, TexxStartup.getLastProjectName()+"/data/raw/") ;
			
			println("active folder   : "+ dir ) ;
		}

	}
	
	public void keyPressed() {

		
		if (key=='b'){
			
			boolean rB=false ; 
			looping = false;
			this.noLoop();

			if (IniProperties.lastProjectName.length()==0){
				try {
					TexxStartup.selectActiveProject();
					IniProperties.appInfo = "itexx"; // that's important for folder maintenance
					                                 // e.g. determining the location of the storage dbs
					rB=true;
				} catch (Exception e) {
					rB=false;
				}
			}else{
				rB=true;
			}
			
			
			if ((rB) && ( IniProperties.dataSource.length()==0)){
				
				key=0;
				rB = TexxStartup.introduceDataSet().length() > 0 ;
			}
			looping = true;
			this.loop() ;
			
			if (rB){
				// startEngines(3) ; // 1=single source;  2=batch from dir;  3=batch from db
				startEngines( 3); // =3
			}else{
				println("unable to start the engine.");
			}
			
		}
		if (key=='t'){
			
			boolean rB=false ; 
			looping = false;
			this.noLoop();
			
			IniProperties.appInfo = "standalone";
			if (IniProperties.lastProjectName.length()==0){
				try {
					TexxStartup.selectActiveProject();
					rB=true;
				} catch (Exception e) {
					rB=false;
				}
			}else{
				rB=true;
			}
			
			
			if ((rB) && ( IniProperties.dataSource.length()==0)){
				
				key=0;
				rB = TexxStartup.introduceDataSet().length() > 0 ;
			}
			looping = true;
			this.loop() ;
			
			if (rB){
				startEngines(1) ; // 1=single source;  2=batch from dir;  3=batch from db
				
			}else{
				println("unable to start the engine.");
			}
		}
		
		if (key=='d'){
			// open data source
			key=0;
			 
			looping = false;

			String datasrc = TexxStartup.introduceDataSet() ;
			System.err.println("File selected as source : "+datasrc);
			
			looping = true;
			this.loop() ;
		}
		
		if (key=='o'){
			// open project
			openProject(); 
			// IniProperties behaves very crazy on external jar !!
			// D:\dev\publish\googlecode\iTexx\noodependencies\NooLabUtilities.jar\~nooTxx-ini.properties 
			// (The system cannot find the path specified)

			// it uses the path of the jar file, not of the main class...
		}
		
		if (key=='p'){ //select a different base folder for projects
			 
			looping = false;
			key=0;
			String selectedFolder;
			try {
				selectedFolder = TexxStartup.selectProjectHome();

			} catch (Exception e) {
				System.err.println(e.getMessage());
				return;
			}
			System.err.println("Folder selected as base folder for projects : "+selectedFolder);
			
			looping = true;
			this.loop() ;
		}
		
		if (key=='P'){ // capital "P": // create project space...
			
			looping = false;
			this.noLoop();
			key=0;
			try {
			
				String psLabel = TexxStartup.getNewProjectSpaceLabel();
				
				if (TexxFactory.projectSpaceExists(psLabel)){
					return;
				}

				IniProperties.lastProjectName = psLabel ;
				TexxFactory.completeProjectSpace();
			 
				System.err.println("Folder selected as new project space : "+TexxStartup.getProjectBasePath() + psLabel);
				
				// now we offer a file selection dialog, which will copy 
				TexxFactory.organizeRawProjectData();
					
				
				
			} catch (Exception e) {
				System.err.println(e.getMessage());
			}
			
			looping = true;
			this.loop() ;
			
		}
		if (key=='x'){
			IniProperties.saveIniProperties();

			System.exit(0);
		}


	}
	
	
	/**
	 * 
	 * @param somtype 0=default: simple, single run; 1=som optimizer
	 * @param lastProjectName2 
	 */
	private void startEngines( int worktype ){
		String str="";
		
		int batchmode = Math.max(0,worktype-1) ;
		if (batchmode>0){ str=" in batch mode";}
		println();
		println("starting project <"+ IniProperties.lastProjectName+">"+str+" ...");
		
		if (worktype>=0){ 
			// worktype = TexxFactory._INSTANCE_TYPE_DEFAULT ;
		}else{
			exit();
		}
		
		texxInstance = new TexxInstance( TexxFactory._GLUE_MODULE_ENV_NONE,
			 							 sourceForProperties ) ;
		
		texxInstance.setBatchMode( batchmode );

		if (worktype==3){
			texxInstance.setSourceMode( TexxTaskIntf._TEXXTASK_SOURCE_TYPE_DB ) ; 
		}
		if (worktype<3){
			texxInstance.setSourceMode( TexxTaskIntf._TEXXTASK_SOURCE_TYPE_FILE ) ; 
		}
		

		
		texxInstance.startInstance() ;
	}
	
	private void openProject(){
		
		looping = false;
		this.noLoop(); // that's mandatory, otherwise, the dialog won't be drawn
		
		try {
		
			TexxStartup.selectActiveProject();
			// dependent on context we maintain different folder structures...
			// either :  base / project / data
			//     or    iTexx/app/Texx   default-prj / data ....
			// actually, we do NOT have data at all
			// such for testing under option "t" we should keep filepath with datafile...
			
		} catch (Exception e) {
			e.printStackTrace();
		}
		 
		looping = true;
		this.loop() ;
		// http://code.google.com/p/processing/source/checkout
	}

	
	
}


class TexxInstance implements   Runnable,
							  	// for messages from the engine to the outer application layers like this module
								TexxApplicationEventIntf{


	TexxFactory    texxFactory;
	TexxProperties texxProperties;
	TexxPropertiesHandler texxPropertiesDefaults;
	
	TexxTaskIntf texxTask;
	boolean batchMode = false;
	int _sourcetype =0;
	
	String sourceForProperties = "";
	
	Thread txxThrd;
	private String lastProjectName;
	private int instanceType;
	private TexxProcessControlIntf txxProcessControl;
	
	
	
	
	// ------------------------------------------------------------------------
	public TexxInstance( int gluemode, String propertiesSource ){
		
		sourceForProperties = propertiesSource;
		
		txxThrd = new Thread(this, "TexxInstance");
	}

	
	
	public void setSourceMode(int sourcetype) {
		_sourcetype =sourcetype ;
	}



	public void setBatchMode(int batchmode) {
		
		batchMode = batchmode>=1 ;
		// ==1 -> from directory
	}



	public void startInstance() {

		lastProjectName = IniProperties.lastProjectName ;
		txxThrd.start();
	
	}
	// ------------------------------------------------------------------------
	
	
	
	
	
	
	@Override
	public void run() {

		if (instanceType == TexxFactory._INSTANCE_TYPE_DEFAULT){
			prepareTexxer();
			createStartTask();
		}
		
	}
	
	public void issueUserbreak() {
		//  
		if (txxProcessControl!=null){
			txxProcessControl.interrupt(0);
		}else{
			System.err.println("Nothing to stop, <somProcessControl> was not up and running...");
		}
	}

	
	private void prepareTexxer(){

		/*
		 * the basic scheme is always: 
		 * 		1. create properties object (is also loading), 
		 * 		2. create factory, prepare core instance
		 * 		3. start core instance, which contains a task loop
		 *      4. create a task
		 *      5. core will accept task and dispatch to respective objects
		 *      
		 *      
		 * only in this way we will get an application, that could always be on, if needed,
		 * and acting as a service
		 * 
		 */
		sourceForProperties = "" ;
		texxProperties = TexxProperties.getInstance( sourceForProperties ); // not available
		
		// alternatively... load from /resources in jar ...
		 
		
		if ((sourceForProperties.length()==0) || ( texxProperties.initializationOK()==false )){
		
			texxPropertiesDefaults = new TexxPropertiesHandler(texxProperties);
			
			explicitlySettingProperties();
			 
		}

		texxFactory = TexxFactory.get(texxProperties);   // creating the factory; 	
		
		
		texxFactory.saveStartupTrace( TexxFactory._INSTANCE_TYPE_DEFAULT, 
									  texxPropertiesDefaults.getStartupTraceInfo() );

		// now we could save the settings for ensuring smooth restart capabilities
		
		texxProperties.save();
		
		
	}


	private void createStartTask(){
	

		// reading the file "taskscheme.xml" in "<rootdir>/<project>/model"
		TexxControlProperties cp = texxProperties.getControlProperties();
		cp.readSettings(""); // if no file is given, the default name and location will be assumed

		// this contains directory settings, mode of operation (instance, service), inclusions, exclusions

		texxTask = (TexxTaskIntf)texxFactory.createTask( TexxProperties._WORKER_TYPE_DEFAULT, TexxFactory._INSTANCE_TYPE_DEFAULT ); 
		

		texxTask.setContinuity( 1,1) ;   // param1: Level of Spela looping: 1=simple model, 2=checking 
					// 						param2: number of runs: (1,1) building a stable model, then stop 
					//               			(2,500) including screening S1, S2, max 500 steps in S2
					//                         	(2,3,500) max 3 levels in S1
					//      					(2,0,500) no dependency screening, just evo-optimizing
      

		texxTask.setStartMode(1) ;             		// default=1 == starting after producing the FluidSom
			//        <1 == only preparing, incl. 1 elementary run to load the data, 
			//              but not starting the modeling process (v switches in the middle between 3..100)
			//        >100  minimum delay in millis


		texxTask.setBatchMode( batchMode) ;
		texxTask.setSourceType( _sourcetype ) ;  
		
		
		texxFactory.testingTikaServerConnection();
		
		try {
			
			// texxFactory.produce( texxTask );
							// this produces the SomFluid and the requested som-type according to
							// SomFluidProperties._SOMTYPE_MONO, referring implicitly to sfTask; 
			
		} catch (Exception e) {
			e.printStackTrace();
		}          		
		
	 	// if we like to have graphical output, then start the applet for displaying it and 
		// define shake hands by means of GlueClients...

	}
	
	
	
	private void explicitlySettingProperties(){
		
		PersistenceSettings ps;


		
		try {
			// important to identify the startup trace...
			String instance = "txx";
			
			texxPropertiesDefaults.setInstance( instance ,0 ); 
			
			
			
			texxPropertiesDefaults.setDataSourcing( "file",0) ; 						// "file", "db", "xml", [0|1] = online learning switch on/off
			texxPropertiesDefaults.setDataSourceName( IniProperties.dataSource );

			String folder = texxPropertiesDefaults.getSupervisedDirectory();  		// ... also available: setSupervisedDirectory(""); 

			
			// optional, if there are indeed plugin files ...
			texxPropertiesDefaults.setAlgorithmsConfigPath( "D:/dev/java/texx/plugins/" );
			

			
			// texxProperties.addFilter( "var",0.3,"<",1,1,true);       
									// filter that act on the values of observations
			   						// can be defined only with an existing factory since we need access to the data
			   						// !! not yet functional

			
			texxPropertiesDefaults.initializeDefaults();
			
			
			// controlling the granularity/verbosity of console messages 
			if (LogControl.Level>2){
				texxProperties.setShowSomProgress( TexxProperties._TXX_DISPLAY_PROGRESS_STEPS ) ; // default: _SOMDISPLAY_PROGRESS_BASIC
			}
			texxProperties.setShowSomProgress( TexxProperties._TXX_DISPLAY_PROGRESS_STEPS );
			
			texxProperties.setMultiProcessingLevel(0); 
			
		} catch (Exception e) {
			e.printStackTrace();
			System.err.println("The system will exit.");
			System.exit(-7) ;
		}
		
		// --- --- ---

		/*
		 * in this folder there will be enumerated sub-folders containing the results
		 */
		String resultFolder = texxPropertiesDefaults.setResultsPersistence(1);	// optionally: a dedicated path
		       resultFolder = texxPropertiesDefaults.getResultBaseFolder();

		// set ready flag
		texxProperties.setInitializationOK(true) ;						
	}
	
	
}